﻿
Ext.baseClass = function () { };
JsonRpc = {};
JsonRpc.Errors = {
    ParseError: -32700,
    InvalidRequest: -32600,
    InvalidData: - 32701
};

JsonRpc.callEvents = function (req, json, initialOptions)
{
    if (!req) return;

    if (req.callback)
        req.callback.call(req.scope, json, initialOptions);

    if (json.error != null)
    {
        if (req.failure)
            req.failure.call(req.scope, json.error, initialOptions);
    }
    else
    {
        if (req.success)
            req.success.call(req.scope, json.result, initialOptions);
    }

    if (req.events)
    {
        for (var i = 0, events = req.events, l = events.length; i < l; i++)
        {
            this.callEvents(events[i], json, initialOptions);
        }
    }

}
JsonRpc.onCallback = function (options, success, response)
{
    var errorResponse, jsonResponses;

    if (!success)
    {
        var ex =
      	    {
      	        code: JsonRpc.Errors.InvalidRequest,
      	        message: 'Invalid request!',
      	        data: response.status
      	    };
        errorResponse = { error: ex };

    }
    else
    {
        try
        {
            jsonResponses = Ext.decode(response.responseText);
        }
        catch (err)
        {
            var ex =
      	    {
      	        code: JsonRpc.Errors.ParseError,
      	        message: 'Invalid JSON was received by the server!',
      	        data: response.responseText
      	    };
            errorResponse = { error: ex };
        }
    }

    if (errorResponse)
    {
        jsonResponses = [];
        if (options.initialOptions.batch)
        {

            for (var i = 0, batch = options.initialOptions.batch, l = batch.length; i < l; i++)
            {
                jsonResponses.push({ id: batch[i].id, error: errorResponse.error});
            }
        }
        else
        {
            jsonResponses.push({id:options.initialOptions.id, error: errorResponse.error});
        }
    }
    try
    {

        var jsonrpcs, originalOptions;

        if (Ext.isArray(jsonResponses))
        {
            jsonrpcs = jsonResponses;
            originalOptions = options.initialOptions.batch;
        }
        else
        {
            jsonrpcs = [];
            jsonrpcs.push(jsonResponses);
            originalOptions = [];
            originalOptions.push(options.initialOptions);

        }

        var jsonrpc, originalOption;
        for (var i = 0, l = jsonrpcs.length; i < l; i++)
        {
            jsonrpc = jsonrpcs[i];
            ////look for id; the responses may come back in other order
            for (var k = 0, l2 = originalOptions.length; k < l2; k++)
            {
                if (originalOptions[k].id == jsonrpc.id)
                {
                    originalOption = originalOptions[k];
                    break;
                }
            }
            if (originalOption)
            {
                this.callEvents(originalOption, jsonrpc, originalOption);
                this.callEvents(originalOption.$internal, jsonrpc, originalOption);
            }
        }
    }
    catch (err)
    {
        throw {
            code: JsonRpc.Errors.InvalidData,
            message: "Data comming from the server cannot be used!",
            data: response.responseText
        };
    }

}

JsonRpc.currentId = 0;
JsonRpc.getNextId = function ()
{
    return JsonRpc.currentId++;
}

JsonRpc.defaultOptions = {
    method: 'POST',
    headers: { "Content-Type": "application/json; charset=utf-8" },
    success: null,
    failure: null,
    callback: JsonRpc.onCallback,
    scope: JsonRpc
}

JsonRpc.call = function (options)
{
    var reqParams = { initialOptions: {} };
    Ext.apply(reqParams.initialOptions, options);
    Ext.apply(reqParams, options, this.defaultOptions);
    reqParams.success = null;
    reqParams.failure = null;
    reqParams.callback = null;
    Ext.apply(reqParams, this.defaultOptions);
    var rpcParams = {
        jsonrpc: "2.0",
        method: options.method,
        params: options.params,
        id: options.id || this.getNextId()
    };

    reqParams.params = Ext.util.JSON.encode(rpcParams);

    Ext.Ajax.request(reqParams);

}

JsonRpc.callBatch = function (options)
{
    var reqParams = { initialOptions: {} };
    Ext.apply(reqParams.initialOptions, options);
    Ext.apply(reqParams, options, this.defaultOptions);
    reqParams.success = null;
    reqParams.failure = null;
    reqParams.callback = null;
    Ext.apply(reqParams, this.defaultOptions);

    var b = options.batch;
    var batchParams = [];
    for (var i = 0; i < b.length; i++)
    {
        var rpcParams = {
            jsonrpc: "2.0",
            method: b[i].method,
            params: b[i].params,
            id: b[i].id || this.getNextId().toString()
        };
        reqParams.initialOptions.batch[i].id = rpcParams.id;
        batchParams.push(rpcParams);
    }

    reqParams.params = Ext.util.JSON.encode(batchParams);

    Ext.Ajax.request(reqParams);

}

JsonRpc.call = function (options)
{
    var reqParams = { initialOptions: {} };
    Ext.apply(reqParams.initialOptions, options);
    Ext.apply(reqParams, options, this.defaultOptions);
    reqParams.success = null;
    reqParams.failure = null;
    reqParams.callback = null;
    Ext.apply(reqParams, this.defaultOptions);

    var b = options.batch || options.methods;


    if (b)
    {
        var batchParams = [];
        for (var i = 0; i < b.length; i++)
        {
            var rpcParams = {
                jsonrpc: "2.0",
                method: b[i].method,
                params: b[i].params,
                id: b[i].id || this.getNextId()
            };
            reqParams.initialOptions.batch[i].id = rpcParams.id;
            batchParams.push(rpcParams);
        }

        reqParams.params = Ext.util.JSON.encode(batchParams);
    }
    else
    {

        var rpcParams = {
            jsonrpc: "2.0",
            method: options.method,
            params: options.params,
            id: options.id || this.getNextId()
        };

        reqParams.params = Ext.util.JSON.encode(rpcParams);
    }

    Ext.Ajax.request(reqParams);

}

JsonRpc.Service = Ext.extend(Ext.baseClass,
{
    $methods: null,
    $callbackSuffix: "Completed",
    $callbackSuccessSuffix: "Success",
    $callbackFailedSuffix: "Failed",

    createArgs: function (functionArgs)
    {
        var newArgs = [];
        for (var i = 0; i < functionArgs.length; i++)
            newArgs.push(functionArgs[i]);

        return newArgs;
    },


    $call: function (options)
    {
        var req = {
            url: this.$url,
            batch: [],
            scope: this
        };

        var methods = [];

        for (var method in options)
        {

            var methodParams = 0;
            if (this.$methods)
            {
                for (var m in this.$methods)
                {
                    if (this.$methods[m].name == method)
                    {
                        methodParams = this.$methods[m].params.length;
                        break;
                    }
                }
            }

            var methodReq;

            methodReq = {
                method: method,
                params: options[method],
                $internal: {
                    callback: this[method + this.$callbackSuffix],
                    success: this[method + this.$callbackSuccessSuffix],
                    failure: this[method + this.$callbackFailedSuffix],
                    scope: this
                }

            };

            var params = options[method];
            if (params.length > methodParams)
            {
                var opt = params[params.length - 1];
                methodReq.params = methodReq.params.slice(0, params.length - 1);
                Ext.apply(methodReq, opt);
            }



            methods.push(methodReq);
        }
        if (methods.length > 0)
        {
            req.batch = methods;
        }

        JsonRpc.callBatch(req);

    }
});

